package cn.biplam.common.wrapper.tree;

import java.util.ArrayList;

import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;

/**
 * 树数据结构，提供将关系数据库的父子结构转换成链表结构，同时提供树的查询、获取树的子树、获取树形结构平面化数据等功能
 * @author XiaoRuxing 2009-5-20下午03:48:30
 * @version 1.0
 */
public class TreeStructre {

	/** 链表结构类 */
	private LinkList list=null;
	/** 树形数据 */
	private ArrayList<String[]> data;

	/**
	 * 
	 */
	public TreeStructre(){
		this.list = new LinkList();
		data=new ArrayList<String[]>();
	}

	/**
	 *  传入链表创建
	 * @param list 链表
	 */
	public TreeStructre(LinkListNode<TreeNode> list){
		this.list = new LinkList(list);
		data=new ArrayList<String[]>();
	}
	
	/**
	 * 插入节点到表头 
	 * @param node 节点
	 */
	public void insertHead(TreeNode node){
		this.list.insertHead(node);
	}

	/**
	 * 插入一个节点到树
	 * @param node 节点
	 * @throws ErrorMessage
	 */
	public void insert(TreeNode node) throws ErrorMessage{
		this.list.insert(node);
	}

	/**
	 * 获取所有父亲节点ID
	 * @param nodeID
	 * @return	String[]
	 */
	public String[] getParents(String nodeID){
		LinkListNode<TreeNode> node=list.getNode(nodeID);
		ArrayList<String> parents=new ArrayList<String>();
		TreeNode treeNode = null;
		while(!list.isRoot(node)){
			node=node.getPreNodes();
			treeNode = node.getData();
			if(treeNode == null){
				break;
			}else{
				parents.add(treeNode.getNodeID());
			}
		}
		return TOOLS.listToStringArray(parents);
	}

	/**
	 * 获取指定节点下所有节点
	 * @param nodeID 节点ID
	 * @return 指定节点下所有节点
	 * @throws ErrorMessage 
	 */
	public String[][] getChildren(String nodeID) throws ErrorMessage{
		return this.getChildren(nodeID, "-1");
	}

	/**
	 * 获取当前节点下的指定级别子节点
	 * @param nodeID    当前节点ID
	 * @param levelDown 向下获取的级别数  -1 全部 0 当前  1 当前节点下1级 2当前节点向下2级 ... n当前节点向下n级
	 * @return 当前节点下的指定级节点
	 * @throws ErrorMessage 
	 */
	public String[][] getChildren(String nodeID,String levelDown) throws ErrorMessage{
		_generatorFlatData(list.getHead().getNextNodes());
		ArrayList<TreeNode> nodes=new ArrayList<TreeNode>();
		list.getChildren(nodeID, nodes,TOOLS.stringToInt(levelDown));
		String[][] nodeData=new String[nodes.size()][];
		for(int i=0;i<nodes.size();i++){
			nodeData[i]=nodes.get(i).getStingArray();
		}
		return nodeData;
	}

	/**
	 * 获取单个指定节点
	 * @param nodeID 节点ID
	 * @return 返回指定节点
	 * @throws ErrorMessage 
	 */
	public String[][] getNode(String nodeID) throws ErrorMessage{
		_generatorFlatData(list.getHead().getNextNodes());
		TreeNode node=list.getNode(nodeID).getData();
		String[][] nodeData=new String[][]{node.getStingArray()};
		return nodeData;
	}

	/**
	 * 将树表数据平面化并放入二维数组容器
	 * @param currentCodes  树容器
	 * @param data          数组容器
	 * @throws ErrorMessage 
	 */
	private void  _generatorFlatData(ArrayList<LinkListNode<TreeNode>> currentCodes) throws ErrorMessage{
		for(LinkListNode<TreeNode> currentNode:currentCodes){
			currentNode.getData().setIsLeaf(getIsLeaf(currentNode));
			currentNode.getData().setIsRoot(getIsRoot(currentNode));
			currentNode.getData().setLevel(getLevel(currentNode));
			currentNode.getData().setSequence(getSequence(currentNode));
			currentNode.getData().setHaveBrother(getHaveBrother(currentNode));
			currentNode.getData().setHaveLBrother(getHaveLbrother(currentNode));
			currentNode.getData().setParentSibling(getParentSibling(currentNode));
			data.add(currentNode.getData().getStingArray());
			_generatorFlatData(currentNode.getNextNodes());
		}
	}

	/**
	 * 获取节点是否是链表头
	 * @param node 节点
	 * @return 节点是否是链表头 
	 */
	public String getIsRoot(LinkListNode<TreeNode> node){
		if(node.getData().getIsRoot()!=null)
			return node.getData().getIsRoot();//外部传入是否为根节点
		String level=getLevel(node);
		if(level.equals("1")){//如果级别为1是根节点
			return "0";
		}else{//如果级别不为1不是根节点
			return "1";
		}
	}

	/** 获取是否是根节点 */
	private boolean isRoot(LinkListNode<TreeNode> node){
		String root=getIsRoot(node);
		if(root.equals("0")){ 
			return true;
		}else{
			return false;
		}
	}

	/**
	 * 获取指定节点层级
	 * @param node 节点
	 * @return 指定节点层级
	 */
	public String getLevel(LinkListNode<TreeNode> node){

		/** 如果当前节点的级别为外部传入，返回外部传入级别 */
		String outLevel=node.getData().getLevel();
		if(outLevel!=null){
			return outLevel;
		}
		if(list.isRoot(node)){//非外部虚根节点
			return "0";
		}else if(node.getPreNodes().isNull()){//无父亲节点0
			return "0";
		}else{//有父亲，父节点Level+1
			TreeNode parent=node.getPreNodes().getData();
			int level=TOOLS.stringToInt(parent.getLevel());
			level++;
			return TOOLS.intToString(level);
		}
	}

	/**
	 * 获取节点是否是链表尾
	 * @param node 节点
	 * @return 节点是否是叶子点 
	 */
	public String getIsLeaf(LinkListNode<TreeNode> node){
		if(node.getData().getIsLeaf()!=null)
			return node.getData().getIsLeaf();//外部传入是否为叶子点
		if(node.getNextNodes().size()>0){
			return "1";
		}else{
			return "0";
		}
	}

	/**
	 * 获取节点兄弟中的排序号<br>
	 *  <ul>如果是根节点返回1
	 *  <ul>返回在兄弟中的排序
	 * @param node 节点
	 * @return 返回节点在兄弟中的排序
	 * @throws ErrorMessage 
	 */
	public String getSequence(LinkListNode<TreeNode> node) throws ErrorMessage{
		if(node.getData().getSequence()!=null)
			return node.getData().getSequence();//排序为外部传入返回外部排序号
		if(this.isRoot(node)){
			return "1";
		}else{
			if(node.getPreNodes()==null)throw new ErrorMessage("Node "+node.data.getNodeID()+" Parent is null at TreeStructre!");
			LinkListNode<TreeNode> parent=node.getPreNodes();
			return TOOLS.intToString(parent.getNextNodes().indexOf(node));
		}
	}

	/**
	 * 获取指定节点是否有哥哥<br>
	 *  <ul>如果是否有哥哥不为空返回
	 *  <ul>如果是根节点则无哥哥
	 *  <ul>如果节点在兄弟中排序老大则无哥哥，否则有哥哥
	 * @param node 节点
	 * @return 指定节点是否有哥哥
	 */
	public String getHaveBrother(LinkListNode<TreeNode> node){
		if(node.getData().getHaveLBrother()!=null){
			return node.getData().getHaveLBrother();
		}
		if(list.isRoot(node)){
			return "0";
		}else{
			LinkListNode<TreeNode> parent=node.getPreNodes();
			if(parent.getNextNodes().indexOf(node)==0){
				return "0";
			}else{
				return "1";
			}
		}
	}

	/**
	 * 获取指定节点是否有弟弟<br>
	 *  <ul>如果有弟弟不为空则返回
	 *  <ul>如果是根节点则无弟弟
	 *  <ul>读取兄弟节点个数，和节点在兄弟中的排名，如果排名小于兄弟个数则有弟弟
	 * @param node 节点
	 * @return 返回节点是否有弟弟
	 */
	public String getHaveLbrother(LinkListNode<TreeNode> node){
		if(node.getData().getHaveLBrother()!=null){
			return node.getData().getHaveLBrother();
		}
		if(list.isRoot(node)){
			return "0";
		}else{
			LinkListNode<TreeNode> parent=node.getPreNodes();
			if(parent.getNextNodes().indexOf(node)==parent.getNextNodes().size()-1){
				return "0";
			}else{
				return "1";
			}
		}
	}

	/**
	 * 获取指定节点的所有父亲节点是否有兄弟
	 * @param node 节点
	 * @return 指定节点所有父亲节点是否有兄弟
	 */
	public ArrayList<String> getParentSibling(LinkListNode<TreeNode> node){
		if(node.getData().getParentSibling()!=null) return node.getData().getParentSibling();
		ArrayList<String> sibling=new ArrayList<String>();
		if(isRoot(node)){
			return sibling;
		}else{	
			TreeNode parent=node.getPreNodes().getData();
			if(parent!=null){
				if(parent.getParentSibling()!=null){
					sibling.addAll(parent.getParentSibling());
				}
				sibling.add(parent.getHaveLBrother());
			}else{
				return node.getData().getParentSibling();
			}
		}
		return sibling;
	}
}
